package com.ngc.mall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ngc.mall.bo.OrderMessageBO;
import com.ngc.mall.common.configure.exception.BusinessException;
import com.ngc.mall.common.configure.mybatisPlus.BaseServiceImpl;
import com.ngc.mall.common.configure.response.ResponseCode;
import com.ngc.mall.core.enumeration.CouponDateType;
import com.ngc.mall.core.enumeration.CouponStatus;
import com.ngc.mall.core.enumeration.CouponType;
import com.ngc.mall.domain.CategoryDomain;
import com.ngc.mall.domain.CouponDomain;
import com.ngc.mall.domain.UserCouponDomain;
import com.ngc.mall.dto.CouponDTO;
import com.ngc.mall.dto.CouponFilterDTO;
import com.ngc.mall.mapper.CouponMapper;
import com.ngc.mall.service.ICategoryService;
import com.ngc.mall.service.ICouponService;
import com.ngc.mall.service.IUserCouponService;
import com.ngc.mall.util.CommonUtil;
import com.ngc.mall.vo.CouponCategoryVO;
import com.ngc.mall.vo.PagingVO;
import com.ngc.mall.vo.UserCouponVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class CouponServiceImpl extends BaseServiceImpl<CouponMapper,CouponDomain> implements ICouponService {

    @Resource
    private ICategoryService iCategoryService;

    @Resource
    private IUserCouponService iUserCouponService;

    @Autowired
    @Qualifier("redisTemplate10")
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public List<CouponDomain> findAllCoupon(){
        return super.list(Wrappers.<CouponDomain>lambdaQuery().orderByDesc(CouponDomain::getCreateTime));
    }

    @Override
    public List<CouponDomain> findDaysCoupon(){
        return super.list(Wrappers.<CouponDomain>lambdaQuery().eq(CouponDomain::getDateType,CouponDateType.DAYS.getValue()));
    }

    @Override
    public Boolean expire(Long cid, Long uid) {
        return iUserCouponService.update(Wrappers.<UserCouponDomain>lambdaUpdate().eq(UserCouponDomain::getStatus,CouponStatus.AVAILABLE.getValue()).set(UserCouponDomain::getStatus,CouponStatus.EXPIRED.getValue()));
    }

    @Override
    public PagingVO<CouponDomain> search(CouponFilterDTO dto, int start, int count) {
        Page<CouponDomain> page=new Page<>(start,count);
        LambdaQueryWrapper<CouponDomain> queryWrapper=Wrappers.<CouponDomain>lambdaQuery().orderByDesc(CouponDomain::getCreateTime);
        if(dto.getCouponType()!= CouponType.ALL.getValue()&&dto.getCouponType()!=null){
            queryWrapper.eq(CouponDomain::getType,dto.getCouponType());
        }
        if(dto.getDateType()!=null){
            queryWrapper.eq(CouponDomain::getDateType,dto.getDateType());
        }
        if(dto.getWholeStore()!=null){
            queryWrapper.eq(CouponDomain::getWholeStore,dto.getWholeStore());
        }
        if(StringUtils.isNotBlank(dto.getStartDate().toString())&&StringUtils.isNotBlank(dto.getEndDate().toString())){
            queryWrapper.ge(CouponDomain::getCreateTime,dto.getStartDate()).le(CouponDomain::getCreateTime,dto.getEndDate());
        }
        IPage iPage=super.page(page,queryWrapper);
        PagingVO<CouponDomain> pagingVO=new PagingVO<>(iPage);
        return pagingVO;
    }

    @Override
    public Boolean deleteCouponTemplateById(Long id) {
        return iUserCouponService.removeById(id);
    }

    @Override
    public List<CouponDomain> getByCategory(Long cid, LocalDateTime now) {
        return baseMapper.findByCategoryId(cid,now);
    }

    @Override
    public List<CouponDomain> findAllEnableCoupon() {
        List<CouponDomain> couponList=super.list();
        List<CouponDomain> couponVOList=new ArrayList<>();
        LocalDateTime now=LocalDateTime.now();
        for(CouponDomain couponDomain:couponList){
          if(couponDomain.getDateType()==CouponDateType.INTERVAL.getValue()){
              Boolean isIn=CommonUtil.isInTimeLine(now,couponDomain.getStartDate(),couponDomain.getEndDate());
              if(isIn){
                couponVOList.add(couponDomain);
              }
          }
          if(couponDomain.getDateType()==CouponDateType.DAYS.getValue()){
              couponVOList.add(couponDomain);
          }
        }
        return couponVOList;
    }

    @Override
    public List<UserCouponVO> getMyAvaliableCouponWithCategory(Long uid, LocalDateTime now) {
        List<UserCouponVO> userCouponVOList=this.findMyAvailable(uid,now);
        for(UserCouponVO userCouponVO:userCouponVOList){
            userCouponVO.setCategoryList(baseMapper.findCategoryListByCouponId(userCouponVO.getId()));
        }
//
        return userCouponVOList;
    }

    @Override
    @Transactional
    public Long createCoupon(CouponDTO dto){
            CouponDomain domain= CouponDomain.builder()
                    .name(dto.getName())
                    .type(dto.getType())
                    .dateType(dto.getDateType())
                    .days(dto.getDays())
                    .startDate(dto.getStartDate())
                    .endDate(dto.getEndDate())
                    .dateType(dto.getDateType())
                    .description(dto.getDescription())
                    .rate(dto.getRate())
                    .minus(dto.getMinus())
                    .wholeStore(dto.getWholeStore())
                    .fullMoney(dto.getFullMoney())
                    .remark(dto.getRemark())
                    .build();
        Long couponId = super.create(domain);
        if(dto.getCategoryIdList()!=null&&!dto.getCategoryIdList().isEmpty()){
            baseMapper.insertCouponCategories(dto.getCategoryIdList(),couponId);
        }
        ///事务回滚
        return couponId;
    }

    public List<CouponDomain> findByCategory(Long cid, LocalDateTime now){
        return baseMapper.findByCategoryId(cid,now);
    }

    @Override
    public List<CouponDomain> findWholeStore(LocalDateTime now){
        return super.list(Wrappers.<CouponDomain>lambdaQuery().eq(CouponDomain::getWholeStore,1).lt(CouponDomain::getStartDate,now).gt(CouponDomain::getEndDate,now));
    }

    @Override
    public List<UserCouponVO> findMyAvailable(Long userId,LocalDateTime now){
        List<UserCouponVO> couponAvailableList=new ArrayList<>();
//        List<UserCouponDomain> userCouponDomainList=iUserCouponService.list(Wrappers.<UserCouponDomain>lambdaQuery().eq(UserCouponDomain::getStatus,CouponStatus.AVAILABLE.getValue()).lt(UserCouponDomain::getStartDate,now).gt(UserCouponDomain::getEndDate,now).eq(UserCouponDomain::getUserId,userId));
        List<UserCouponDomain> userCouponDomainList=iUserCouponService.list(Wrappers.<UserCouponDomain>lambdaQuery().eq(UserCouponDomain::getStatus,CouponStatus.AVAILABLE.getValue()).isNull(UserCouponDomain::getOrderId).eq(UserCouponDomain::getUserId,userId));
        ///判断过期
        for(UserCouponDomain userCouponDomain:userCouponDomainList){
            Boolean isIn= CommonUtil.isInTimeLine(now,userCouponDomain.getStartDate(),userCouponDomain.getEndDate());
            if(isIn){
                CouponDomain couponDomain=super.getOne(Wrappers.<CouponDomain>lambdaQuery().eq(CouponDomain::getId,userCouponDomain.getCouponId()));
                if(couponDomain!=null){
                    UserCouponVO userCouponVO=UserCouponVO.builder().userId(userId).startDate(userCouponDomain.getStartDate()).endDate(userCouponDomain.getEndDate()).description(couponDomain.getDescription()).id(couponDomain.getId()).name(couponDomain.getName()).fullMoney(couponDomain.getFullMoney()).minus(couponDomain.getMinus()).rate(couponDomain.getRate()).type(couponDomain.getType()).wholeStore(couponDomain.getWholeStore()).build();
                    couponAvailableList.add(userCouponVO);
                }
            }else{

            }
        }
        return  couponAvailableList;
    }

    @Override
    public List<UserCouponVO> findMyUsed(Long userId,LocalDateTime now){
        List<UserCouponVO> couponUsedList=new ArrayList<>();
        List<UserCouponDomain> userCouponDomainList=iUserCouponService.list(Wrappers.<UserCouponDomain>lambdaQuery().eq(UserCouponDomain::getStatus,CouponStatus.USED.getValue()).isNotNull(UserCouponDomain::getOrderId).eq(UserCouponDomain::getUserId,userId));
        for(UserCouponDomain userCouponDomain:userCouponDomainList){
            CouponDomain couponDomain=super.getOne(Wrappers.<CouponDomain>lambdaQuery().eq(CouponDomain::getId,userCouponDomain.getCouponId()));
            if(couponDomain!=null){
                UserCouponVO userCouponVO=UserCouponVO.builder().userId(userId).startDate(userCouponDomain.getStartDate()).endDate(userCouponDomain.getEndDate()).description(couponDomain.getDescription()).id(couponDomain.getId()).name(couponDomain.getName()).fullMoney(couponDomain.getFullMoney()).minus(couponDomain.getMinus()).rate(couponDomain.getRate()).type(couponDomain.getType()).wholeStore(couponDomain.getWholeStore()).build();
                couponUsedList.add(userCouponVO);
            }
        }
        return  couponUsedList;
    }

    @Override
    public List<UserCouponVO> findMyExpired(Long userId,LocalDateTime now){
        ///判断可用的优惠券有没有过期的
        List<UserCouponVO> couponExpiredList=new ArrayList<>();
        List<UserCouponDomain> userCouponDomainList=iUserCouponService.list(Wrappers.<UserCouponDomain>lambdaQuery().eq(UserCouponDomain::getStatus,CouponStatus.EXPIRED.getValue()).isNull(UserCouponDomain::getOrderId).eq(UserCouponDomain::getUserId,userId));
        for(UserCouponDomain userCouponDomain:userCouponDomainList){
            CouponDomain couponDomain=super.getOne(Wrappers.<CouponDomain>lambdaQuery().eq(CouponDomain::getId,userCouponDomain.getCouponId()));
            if(couponDomain!=null){
                UserCouponVO userCouponVO=UserCouponVO.builder().userId(userId).startDate(userCouponDomain.getStartDate()).endDate(userCouponDomain.getEndDate()).description(couponDomain.getDescription()).id(couponDomain.getId()).name(couponDomain.getName()).fullMoney(couponDomain.getFullMoney()).minus(couponDomain.getMinus()).rate(couponDomain.getRate()).type(couponDomain.getType()).wholeStore(couponDomain.getWholeStore()).build();
                couponExpiredList.add(userCouponVO);
            }
        }
        return couponExpiredList;
    }

    @Override
    public Boolean collectOneCoupon(Long uid,Long couponId,Boolean limit){
        CouponDomain couponDomain=super.check(couponId);
        ///日期类型为区间时，优惠券是否过期
        LocalDateTime now=LocalDateTime.now();
        int dateType=couponDomain.getDateType();
        ///是否是第一次领取优惠券
        if(limit){
            this.findFirstByUserIdAndCouponId(uid,couponId);
        }
        UserCouponDomain userCouponDomain=UserCouponDomain.builder().userId(uid).couponId(couponId).status(CouponStatus.AVAILABLE.getValue()).build();
        String key = couponId.toString() + "," + uid.toString();
        //有限天数
        if(dateType==CouponDateType.DAYS.getValue()){
            LocalDateTime expireDate = now.plusDays(couponDomain.getDays());
            userCouponDomain.setStartDate(now);
            userCouponDomain.setEndDate(expireDate);
        }
        //日期区间
        if(dateType== CouponDateType.INTERVAL.getValue()){
            ///判断优惠券是否在有效时间区间内
            Boolean isIn=CommonUtil.isInTimeLine(now,couponDomain.getStartDate(),couponDomain.getEndDate());
            if(!isIn){
                throw new BusinessException(ResponseCode.COUPON_EXPIRED);
            }
            userCouponDomain.setStartDate(couponDomain.getStartDate());
            userCouponDomain.setEndDate(couponDomain.getEndDate());
        }
        Boolean insertResult=iUserCouponService.save(userCouponDomain);
        return insertResult;
    }

    /**
     * 优惠券只能领取一次
     * @param uid
     * @param couponId
     */
    public void findFirstByUserIdAndCouponId(Long uid,Long couponId){
        UserCouponDomain userCouponDomain=iUserCouponService.getOne(Wrappers.<UserCouponDomain>lambdaQuery().eq(UserCouponDomain::getCouponId,couponId).eq(UserCouponDomain::getUserId,uid));
        if(userCouponDomain!=null){
            throw new BusinessException(ResponseCode.USER_COUPON_EXISTED);
        }
    }
    @Override
    public List<CouponCategoryVO> getUserCouponAvailableWithCategory(Long userId,LocalDateTime now){
        return null;
    }

    @Override
    public CouponDomain findById(Long cid){
        return super.getById(cid);
    }

    @Override
    public List<CategoryDomain> findCategoriesById(Long cid){
        return baseMapper.findCategoryListByCouponId(cid);
    }

    @Override
    public void returnBack(OrderMessageBO orderMessage) {

        Boolean result=iUserCouponService.update(Wrappers.<UserCouponDomain>lambdaUpdate().eq(UserCouponDomain::getCouponId,orderMessage.getCouponId()).eq(UserCouponDomain::getUserId,orderMessage.getUserId()).isNotNull(UserCouponDomain::getOrderId).set(UserCouponDomain::getStatus,CouponStatus.AVAILABLE).set(UserCouponDomain::getOrderId,null));
        if(result){
            System.out.println("退还优惠券失败");
        }
    }
}
